package com.zoe.onelink.plugin.check;

import com.google.common.base.Joiner;
import com.zoe.onelink.enhancer.init.AbstractApplicationInitializer;
import com.zoe.onelink.plugin.check.exception.PropertyCheckException;
import com.zoe.onelink.plugin.check.model.PropertyCheckResult;
import com.zoe.onelink.plugin.check.property.OnelinkCheckerProperties;
import com.zoe.onelink.plugin.check.report.PropertyCheckerReporter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>标题: </p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2022</p>
 * <p>公司: 智业软件股份有限公司</p>
 *
 * @version: 1.0
 * @author: ruansheng
 * @date: 2022-09-19
 */
@Slf4j
@RequiredArgsConstructor
public class ApplicationPropertyCheckerComposite extends AbstractApplicationInitializer {

    private final OnelinkCheckerProperties onelinkCheckerProperties;
    private final List<EnvironmentChecker> environmentCheckers;
    private final List<PropertyCheckerReporter> propertyCheckerReporters;
    private final Environment env;

    @Override
    protected void doInit(ApplicationStartedEvent event) throws Exception {
        List<PropertyCheckResult<?>> checkResults = this.environmentCheckers.stream().flatMap(propertyChecker -> {
            try {
                Profiles checkerActiveProfiles = propertyChecker.enableOnProfiles();
                if (checkerActiveProfiles != null && !this.env.acceptsProfiles(checkerActiveProfiles)) {
                    log.debug("[环境检查模块] [{}] Profiles [{}] 与当前应用 Profiles [{}] 不匹配,已自动跳过",
                            propertyChecker.getClass().getName(), checkerActiveProfiles, Joiner.on(',').skipNulls().join(this.env.getActiveProfiles()));
                    return Stream.empty();
                }
                List<PropertyCheckResult<?>> innerCheckResults = propertyChecker.check();
                return innerCheckResults == null ? Stream.empty() : innerCheckResults.stream();
            } catch (Exception e) {
                log.warn("[环境检查模块] [{}] 检查应用参数配置失败: {}", propertyChecker.getClass().getName(), e.getMessage());
            }
            return Stream.empty();
        }).collect(Collectors.toList());

        // 上报检查结果
        for (PropertyCheckerReporter propertyCheckerReporter : this.propertyCheckerReporters) {
            try {
                propertyCheckerReporter.report(checkResults);
            } catch (PropertyCheckException e) {
                log.error("[环境检查模块] 程序运行环境安全检查不通过,已终止启动,若想关闭该检查," +
                        "请配置[onelink.plugins.checker=false],具体错误信息如下:", e);
                // 调用JVM钩子，停止前会先执行所有PreDestroy方法，并且传递具体的退出码给所有Context。
                // 程序执行完后最后会输出：Process finished with exit code 500，给JVM一个SIGNAL。
                System.exit(500);
            } catch (Exception e) {
                log.error("[环境检查模块] 参数结果上报失败: {}", e.getMessage());
            }
        }

    }

    @Override
    public boolean isAsync() {
        return false;
    }

    @Override
    public boolean throwable() {
        return true;
    }
}
